﻿// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.ComponentModel;
using LIUS.Beta.FileSystem.PathFileSuffix;
// ReSharper restore RedundantUsingDirective

namespace Kopain2
{

    /// <summary>Interaction logic for FormMain.xaml
    /// </summary>
    public partial class FormMain  //: Window
    {

#region	Private properties.

        /// <summary>This is the tree of documents that is shown in the GUI.
        /// </summary>
        private static KopainDocumentTree _documentTree;

        private static MRUList _mruList;

        /// <summary>This is the reference to the repository; or the KopainConcept if you prefer.  I belive this one is going away.
        /// </summary>
        private Repository _repository;

        /// <summary>This is a reference to the statusbar as a guilogic object.  Maybe this will be exchanged for a user control in the future but that depends on how the automatic tests are implemented.
        /// </summary>
        private KopainStatusbar _statusbar;

        ///// <summary>This is a reference to the treeview as a guilogic object.
        ///// </summary>
        //private KopainTreeviewData _treeviewData;

#endregion	//	Private properties.

#region	Public properties.

        /// <summary>This property publishes the documents that are listed in the treeview.
        /// </summary>
        public static KopainDocumentTree TheDocumentTree
        {
            get
            {
                return _documentTree;
            }
        }

        public static XmlDataProvider MenuContentXml
        {
            get
            {
                System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                doc.LoadXml(
                    "<MenuContent>" +
                    "  <Category Title=\"Cat 1\">" +
                    "    <Item Name=\"Item 1\"></Item>" +
                    "    <Item Name=\"Item 2\"></Item>" +
                    "  </Category>" +
                    "  <Category Title=\"Cat 2\">" +
                    "    <Item Name=\"Item 1\"></Item>" +
                    "  </Category>" +
                    "</MenuContent>"
                    );
                XmlDataProvider x = new XmlDataProvider();
                //see http://blogs.msdn.com/llobo/archive/2007/10/23/binding-menus-using-heirarchicaldatatemplates.aspx source
                return x;
            }
        }

        public static List<MenuDataItem> MRUMenuList
        {
            get
            {
                // Create the MRU list once and only once.
                if (null == _mruList)
                {
                    PopulateMRUListMenu(); //    What does this call do?
                }

                // Create the list of data that is "behind" the menu items.
                List<MenuDataItem> ret = new List<MenuDataItem>();
                for (int i = 0; i < _mruList.Count; i++)
                {
                    ret.Add( new MenuDataItem(_mruList[i].Title, _mruList[i].PathFilenameSuffix ));
                }

                return ret;
            }
        }

#endregion	//	Public properties.
        
#region	Constructors.

        public FormMain()
        {
            _statusbar = new KopainStatusbar();
            //_treeviewData = new KopainTreeviewData();
            _documentTree = new KopainDocumentTree();    // We have to set the list to something; otherwise an XamlParseException exception occurs.

            _repository = new Repository();

            InitializeComponent();
        }

#endregion	//	Constructors.

#region	Event handlers.
        
#region	Window event handlers.

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //PopulateMRUListMenu();

            // Create the MRU list menu.
            _mruMenu.DataContext = MRUMenuList;

            if (0 == MRUMenuList.Count)
            {
                 CreateNewConceptAndOpen();
            }
            else
            {
                try
                {
                    OpenConcept(MRUMenuList[0].PathFilenameSuffix);
                }
#pragma warning disable 168
                catch (KopainConcept.Exception.FileWasNotFoundException exc)
#pragma warning restore 168
                {
                    // The first Concept in the MRU list could not be opened at startup.  It has probably been removed so just create a new Concept instead.
                    _mruMenu.DataContext = MRUMenuList;
                    _mruList.RemoveAt(0);
                    //TODO: Save the new MRU list.  This is written in the readme too.
                    _mruMenu.DataContext = MRUMenuList;
                    CreateNewConceptAndOpen();
                }
            }

            //// Update the Treeview with the Documents in the Concept.
            //_documentTree.ReplaceWith(_repository.DocumentList);
            ////_treeviewData.Populate(_documentTree);

            // Bind a label in the status bar to the loaded Concept.
            statusbarlblFilename.SetBinding(ContentProperty, _statusbar.CreateFilenameBinding());

            // Set a control to have focus to start with.
            treeviewMain.Focus();
        }

#endregion	//	Window event handlers.

#region	Menu event handlers.

        private void mnuNodeTest_Click(object sender, RoutedEventArgs e)
        {
            _statusbar.Filename = "updated!" + DateTime.Now.ToString();
            TheDocumentTree[0].Children.Add(KopainDocument.CreateDirectory(null, Guid.NewGuid(), "A", new LIUS.Beta.FileSystem.PathFileSuffix.Path("B", HandleValue.RequireExact), true));
        }

        private void mnuRecentFileItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem menuItem = (MenuItem)sender;
            OpenConcept
            (
                ((MenuDataItem)menuItem.Header).PathFilenameSuffix
            );
        }

        private void OnMenuDataItemLoaded(object sender, RoutedEventArgs e)
        {
            //System.Windows.Controls.ContentPresenter presenter = (System.Windows.Controls.ContentPresenter)sender;

            MenuItem menuItem = FindMenuItemAncestor((DependencyObject)sender);

            //CommandBinding cb = new CommandBinding(DataCommands.OpenRecentFile, cb_Executed, cb_CanExecute);
            ////cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
            ////cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute);
            //menuItem.CommandBindings.Add(cb);

            if (null == menuItem.CommandParameter)
            {
                ////TODO:This C: is just for making things work here - exchange to whatever.
                menuItem.CommandParameter = ((Kopain2.MenuDataItem)menuItem.Header).PathFilenameSuffix;   // "C:" + ((Kopain2.MenuDataItem)menuItem.Header).Name;
                menuItem.ToolTip = ((Kopain2.MenuDataItem)menuItem.Header).PathFilenameSuffix.ToString();
                menuItem.Click += new RoutedEventHandler(mnuRecentFileItem_Click);
            }
        }

        private void mnuNewConcept_Click(object sender, RoutedEventArgs e)
        {
            AskUserToCreateNewConcept();
        }

        private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        /// <summary>This is a fork for a whole load of events.
        ///   http://anuraj.wordpress.com/2008/06/23/shortcuts-keys-in-wpf-menu/
        ///   http://en.csharp-online.net/WPF_Concepts—Built-In_Commands
        ///   http://colbycavin.spaces.live.com/blog/cns!5FFDF795EBC7BEDF!129.entry
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Command.Equals(ApplicationCommands.Close))
            {
                //private void mnuExit_Click(object sender, RoutedEventArgs e)
                //{
                //    CloseApplication();
                //}
                CloseApplication();
            }
            else if (e.Command.Equals(ApplicationCommands.Open))
            {
                //private void mnuOpenConcept_Click(object sender, RoutedEventArgs e)
                //{
                //    AskUserForConceptToOpen();
                //}
                AskUserForConceptToOpen();
            }
            else if (e.Command.Equals(ApplicationCommands.Save))
            {
                //private void mnuSaveConcept_Click(object sender, RoutedEventArgs e)
                //{
                //    SaveConcept();
                //}
                SaveConcept();
            }
            else if (e.Command.Equals(Kopain2Commands.About))
            {
                //private void mnuAbout_Click(object sender, RoutedEventArgs e)
                //{
                //    Forms.FormAbout frm = new Kopain2.Forms.FormAbout();
                //    frm.ShowDialog();
                //}
                Forms.FormAbout frm = new Kopain2.Forms.FormAbout();
                frm.ShowDialog();
            }
        }

#endregion	//	Menu event handlers.

        private void treeviewMain_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            KopainDocument doc = GetSelectedDocumentInTreeView();
            if (null == doc)
            {
                const string noDocumentText = "no document";
                _statusbar.Filename = noDocumentText;
                _editor.Populate(noDocumentText);
            }
            else
            {
                _statusbar.Filename = doc.Name;

                //  Find the Document shown.
                var document = GetSelectedDocumentInTreeView();
                var note = _repository.Concept.FindNoteByID(document.ID);
                note.Open(_repository.Concept.PathFilenameSuffix.Path, KopainConcept.Concept.Note.ForceOpen.Yes);
                _editor.Populate(note.Data);
                //_editor.Populate(GetSelectedDocumentInTreeView().Name);
            }
        }

#endregion	//	Event handlers.

#region	Presentation methods.

        private void AskUserForConceptToOpen()
        {
            PathFilenameSuffix pathFilenameSuffix = null;
            System.Windows.Forms.DialogResult dialogResult = System.Windows.Forms.DialogResult.None;

            using (System.Windows.Forms.OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog())
            {
                dlg.Filter = Properties.Settings.Default.FileOpenFilter;
                dialogResult = dlg.ShowDialog();
                if (System.Windows.Forms.DialogResult.OK == dialogResult)
                {
                    pathFilenameSuffix = new PathFilenameSuffix(dlg.FileName, HandleValue.RequireExact);
                }
            }
            if (System.Windows.Forms.DialogResult.OK == dialogResult)
            {
                OpenConcept(pathFilenameSuffix);
            }
        }

        /// <summary>This method asks the user whether to create a new file.
        /// </summary>
        private void AskUserToCreateNewConcept()
        {
            //TODO:Ask the user.
            //TODO:Save existing file.

            CreateNewConceptAndOpen();
        }

        /// <summary>This method closes the application and does the tidying up like saving the last used file.
        /// </summary>
        private void CloseApplication()
        {
            //TODO:Update the MRU list.
            this.Close();
        }

        /// <summary>This method creates a new Concept.  If the user should be asked, call AskUserToCreateNewConcept instead.
        /// </summary>
        private void CreateNewConceptAndOpen()
        {
            // Create the file.
            var concept = Repository.CreateNew();
            //_concept = KopainConcept.Concept.CreateNew();

            //_repository.Save();   //  This should be done implicitly by CreateNew.

            // Load the file into the GUI.
            OpenConcept(concept.PathFilenameSuffix); // _repository.Concept.PathFilenameSuffix);
        }

        /// <summary>This method opens the Concept which is specified in the parameter.
        /// </summary>
        /// <param name="pathFilenameSuffix"></param>
        private void OpenConcept(PathFilenameSuffix pathFilenameSuffix)
        {
            _repository.Open(pathFilenameSuffix);
            //_concept = KopainConcept.Concept.Open(pathFilenameSuffix);
            _documentTree.Populate(_repository.Concept);
            SelectFirstItemInTreeView();
        }

        /// <summary>This method populates the MRUList private property.
        /// </summary>
        private static void PopulateMRUListMenu()
        {
            _mruList = MRUList.Populate();
            for (int i = 0; i < _mruList.Count; i++)
            {
            //    string pathAndFile = mruList.PathAndFileList[i];
            //    //MenuItem menuItem = new MenuItem();
            //    //menuItem.Header = pathAndFile;
            //    //menuItem.Click += new RoutedEventHandler(mnuRecentFile_Click);
            //    ////mnuRecentFiles.Items.Add(menuItem);
            }
            //mruList.PathAndFileList.Add("my file");
            //mruList.Save();
        }

        /// <summary>This method saves the Concept.
        /// </summary>
        private void SaveConcept()
        {
            KopainDocument selectedDocument = GetSelectedDocumentInTreeView();

            // Copy the text in the editor into the correct Concept Note.
            _repository.Concept.FindNoteByID(selectedDocument.ID).Data = _editor.PlainText;

            // Ask the Concept to persist itself.
            _repository.Save();
            
            // What does this row do?
            //selectedDocument.Path = _concept.PathFilenameSuffix.Path;

            // Update the MRU list.
            _mruList.Add(new MRUItem(_repository.Concept.PathFilenameSuffix.Filename.ToString(), _repository.Concept.PathFilenameSuffix));   // Setting Filename as Title, is it correct?
            _mruList.Save();
        }

        /// <summary>This method selects the first item in the treeview.  It can with fördel be moved to a custom treeview class.
        /// </summary>
        private void SelectFirstItemInTreeView()
        {
            SelectItemInTreeView(_documentTree[0]);
        }

        /// <summary>This method selects one of the items in the treeview.  It can with fördel be moved to a custom treeview class.
        /// http://ewilkerson.wordpress.com/2007/04/20/how-to-programmatically-change-the-selecteditem-in-a-wpf-treeview/
        /// http://askernest.com/archive/2008/01/23/how-to-programmatically-change-the-selecteditem-in-a-wpf-treeview.aspx
        /// </summary>
        /// <param name="item"></param>
        private void SelectItemInTreeView(KopainDocument item)
        {
            DependencyObject dependencyObject = treeviewMain.ItemContainerGenerator.ContainerFromItem(item);
            //((TreeViewItem)dependencyObject).IsSelected = true;
            System.Reflection.MethodInfo selectMethod = typeof(TreeViewItem).GetMethod("Select", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            selectMethod.Invoke(dependencyObject, new object[] { true });
        }

#endregion	//	Presentation methods.

#region	Helper methods.

        private static MenuItem FindMenuItemAncestor(DependencyObject dependencyObject)
        {
            while (null != dependencyObject)
            {
                MenuItem menuItem = dependencyObject as MenuItem;
                if (null != menuItem) { return menuItem; }
                dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
            }
            return null;
        }

        /// <summary>This method returns the selected item in the treeview properly type casted.  Please move this to a custom control for the treeview.
        /// </summary>
        /// <returns></returns>
        private KopainDocument GetSelectedDocumentInTreeView()
        {
            return (KopainDocument)treeviewMain.SelectedItem;
        }

#endregion	//	Helper methods.

    }

}
